/***************************************************************************
 *   Copyright (C) 2009 by Marian Skvarek   *
 *   skvarek.marian@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A TrackICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "CEasyScoreMainWindow.h"
#include "CEasyScoreApp.h"
#include "CScore.h"
#include "CScoreView.h"
#include "CGraphicsView.h"
#include "CGlobals.h"
#include "CDebug.h"


#include <QtGui>
#include <QTextStream>

using namespace easyscore::gui;
using namespace easyscore::utils;
using namespace easyscore::globals;

namespace easyscore
{

    CEasyScoreMainWindow::CEasyScoreMainWindow ( CEasyScoreApp *app )
    {
        mApp = app;
    }

    CEasyScoreMainWindow::~CEasyScoreMainWindow()
    {

    }

    void CEasyScoreMainWindow::initialize()
    {
        this->setWindowState ( Qt::WindowMaximized );
        QPalette pal = this->palette();
        pal.setColor ( QPalette::Window, Qt::gray );
        this->setPalette ( pal );

        createActions();
        createMenus();
        createToolBars();
        createStatusBar();

        mScoreSceneView = new CGraphicsView();
        setCentralWidget ( mScoreSceneView );

        //TEMP - debug
        //        if ( DEBUG )
        //        {
        //            QDockWidget *q = new QDockWidget;
        //            this->addDockWidget ( Qt::RightDockWidgetArea,q );
        //            QLabel * testLabel = new QLabel();
        //            q->layout()->addWidget ( testLabel );
        //            CDebug::getInstance()->setDebugLabel ( testLabel );
        //        }

        mNote32Action->toggle();
    }

    void CEasyScoreMainWindow::closeEvent ( QCloseEvent *event )
    {
        if ( maybeSave() )
        {
            event->accept();
        }
        else
        {
            event->ignore();
        }
    }

    void CEasyScoreMainWindow::newFile()
    {
        mApp->newScore();
        setCurrentFile("");
    }

    void CEasyScoreMainWindow::open()
    {
        if ( maybeSave() )
        {
            QString fileName = QFileDialog::getOpenFileName ( this );
            if ( !fileName.isEmpty() )
                loadFile ( fileName );
        }
    }

    bool CEasyScoreMainWindow::save()
    {
        if ( mApp->getCurrentFile().isEmpty() )
        {
            return saveAs();
        }
        else
        {
            return saveFile ( mApp->getCurrentFile() );
        }
    }

    bool CEasyScoreMainWindow::saveAs()
    {
        QString fileName =
                QFileDialog::getSaveFileName(this, tr("Save As..."),
                                             QDir::home().path(),
                                             tr("EasyScore project (*.eas)"));
        if (fileName.isEmpty())
            return false;
        if(!fileName.endsWith(".eas"))
            fileName += ".eas";

        QFile file(fileName);

        if(file.exists())
            file.remove();

        if (mApp->save(file))
        {
            statusBar()->showMessage(tr("File saved"), 2000);
            setCurrentFile(fileName);
            return true;
        }
        else
        {
            statusBar()->showMessage(tr("Saving failed"), 2000);
            return false;
        }
    }

    void CEasyScoreMainWindow::print()
    {
        if (mApp->print())
        {
            statusBar()->showMessage(tr("Print successful"), 2000);
            //setCurrentFile(fileName);
            //return true;
        }
        else
        {
            statusBar()->showMessage(tr("Print failed"), 2000);
            //return false;
        }
    }

    void CEasyScoreMainWindow::about()
    {
        QMessageBox::about ( this, tr ( "About EasyScore" ),
                             tr ( "<b> EasyScore </b> notation editor "
                                  "- a smart and easy-to-use tool intended for amateur musicians" )
                             );
    }

    void CEasyScoreMainWindow::documentWasModified()
    {
        setWindowModified ( true );
    }

    void CEasyScoreMainWindow::createActions()
    {
        mNewAction = new QAction ( QIcon ( ":/res/img/actions/filenew.xpm" ), tr ( "&New" ), this );
        mNewAction->setShortcut ( tr ( "Ctrl+N" ) );
        mNewAction->setStatusTip ( tr ( "Create a new file" ) );
        connect ( mNewAction, SIGNAL ( triggered() ), this, SLOT ( newFile() ) );

        mOpenAction = new QAction ( QIcon ( ":/res/img/actions/fileopen.xpm" ), tr ( "&Open..." ), this );
        mOpenAction->setShortcut ( tr ( "Ctrl+O" ) );
        mOpenAction->setStatusTip ( tr ( "Open an existing file" ) );
        connect ( mOpenAction, SIGNAL ( triggered() ), this, SLOT ( open() ) );

        mSaveAction = new QAction ( QIcon ( ":/res/img/actions/filesave.xpm" ), tr ( "&Save" ), this );
        mSaveAction->setShortcut ( tr ( "Ctrl+S" ) );
        mSaveAction->setStatusTip ( tr ( "Save the document to disk" ) );
        connect ( mSaveAction, SIGNAL ( triggered() ), this, SLOT ( save() ) );

        mSaveAsAction = new QAction ( tr ( "Save &As..." ), this );
        mSaveAsAction->setStatusTip ( tr ( "Save the document under a new name" ) );
        connect ( mSaveAsAction, SIGNAL ( triggered() ), this, SLOT ( saveAs() ) );

        mExportToPDFAction = new QAction ( tr ( "PDF" ), this );
        mExportToPDFAction->setStatusTip ( tr ( "Save the document to a pdf document" ) );
        connect ( mExportToPDFAction, SIGNAL ( triggered() ), this, SLOT ( exportToPDF() ) );

        mExportToTabAction = new QAction ( tr ( "Tablature" ), this );
        connect ( mExportToTabAction, SIGNAL ( triggered() ), this, SLOT ( exportToTab() ) );

        mExportToMusicXML = new QAction ( tr ( "MusicXML" ), this );
        connect ( mExportToMusicXML, SIGNAL ( triggered() ), this, SLOT ( exportToMusicXML() ) );

        mExportToPNGAction = new QAction ( tr ( "PNG" ), this );
        connect ( mExportToPNGAction, SIGNAL ( triggered() ), this, SLOT ( exportToPNG() ) );

        mPrintAction= new QAction ( QIcon ( ":/res/img/actions/print.xpm" ), tr ( "&Print" ), this );
        mSaveAsAction->setStatusTip ( tr ( "Print a score..." ) );
        connect ( mPrintAction, SIGNAL ( triggered() ), this, SLOT ( print() ) );

        mExitAction = new QAction ( tr ( "E&xit" ), this );
        mExitAction->setShortcut ( tr ( "Ctrl+Q" ) );
        mExitAction->setStatusTip ( tr ( "Exit the application" ) );
        connect ( mExitAction, SIGNAL ( triggered() ), this, SLOT ( close() ) );

        mAboutAction = new QAction ( tr ( "&About" ), this );
        mAboutAction->setStatusTip ( tr ( "Show the application's About box" ) );
        connect ( mAboutAction, SIGNAL ( triggered() ), this, SLOT ( about() ) );

        mNoteActionGroup = new QActionGroup(this);
        mNoteActionGroup->setExclusive(true);
        connect( mNoteActionGroup, SIGNAL( selected( QAction* ) ), this, SLOT( setCurrentNote( QAction* ) ) );

        mInsertBarAction = new QAction ( tr ( "New bar" ), this );
        mInsertBarAction->setStatusTip ( tr ( "Insert a new bar into score" ) );
        mInsertBarAction->setShortcut ( tr ( "Ctrl+T" ) );
        connect ( mInsertBarAction, SIGNAL ( triggered() ), this, SLOT ( addBar() ) );

        //mNote256Action = new QAction ( QIcon ( ":/res/img/actions/actionNote256.png" ), tr ( "Breve note" ), this );
        //mNote256Action->setStatusTip ( tr ( "Insert a breve note" ) );
        //mNote256Action->setCheckable(true);
        //mNoteActionGroup->addAction(mNote256Action);

        mNote128Action = new QAction ( QIcon ( ":/res/img/actions/actionNote128.png" ), tr ( "Full note" ), this );
        mNote128Action->setStatusTip ( tr ( "Insert a full note" ) );
        mNote128Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote128Action);

        mNote64Action = new QAction ( QIcon ( ":/res/img/actions/actionNote64.png" ), tr ( "Half note" ), this );
        mNote64Action->setStatusTip ( tr ( "Insert a half note" ) );
        mNote64Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote64Action);

        mNote32Action = new QAction ( QIcon ( ":/res/img/actions/actionNote32.png" ), tr ( "Quarter note" ), this );
        mNote32Action->setStatusTip ( tr ( "Insert a quarter note" ) );
        mNote32Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote32Action);

        mNote16Action = new QAction ( QIcon ( ":/res/img/actions/actionNote16.png" ), tr ( "Eighth note" ), this );
        mNote16Action->setStatusTip ( tr ( "Insert an eighth note" ) );
        mNote16Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote16Action);

        mNote8Action = new QAction ( QIcon ( ":/res/img/actions/actionNote8.png" ), tr ( "Sixteenth note" ), this );
        mNote8Action->setStatusTip ( tr ( "Insert a sixteenth note" ) );
        mNote8Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote8Action);

        mNote4Action = new QAction ( QIcon ( ":/res/img/actions/actionNote4.png" ), tr ( "32nd note" ), this );
        mNote4Action->setStatusTip ( tr ( "Insert a 32nd note" ) );
        mNote4Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote4Action);

        mNote2Action = new QAction ( QIcon ( ":/res/img/actions/actionNote2.png" ), tr ( "64th note" ), this );
        mNote2Action->setStatusTip ( tr ( "Insert a 64th note" ) );
        mNote2Action->setCheckable(true);
        mNoteActionGroup->addAction(mNote2Action);

        mZoomInAction = new QAction ( QIcon ( ":/res/img/actions/zoomIn.png" ), tr ( "Zoom in" ), this );
        mZoomInAction->setStatusTip ( tr ( "Zoom In" ) );
        connect ( mZoomInAction, SIGNAL ( triggered() ), this, SLOT ( zoomIn() ) );

        mZoomOutAction = new QAction ( QIcon ( ":/res/img/actions/zoomOut.png" ), tr ( "Zoom out" ), this );
        mZoomOutAction->setStatusTip ( tr ( "Zoom Out" ) );
        connect ( mZoomOutAction, SIGNAL ( triggered() ), this, SLOT ( zoomOut() ) );


    }

    void CEasyScoreMainWindow::createMenus()
    {
        mFileMenu = menuBar()->addMenu ( tr ( "&File" ) );
        mFileMenu->addAction ( mNewAction );
        mFileMenu->addAction ( mOpenAction );
        mFileMenu->addAction ( mSaveAction );
        mFileMenu->addAction ( mSaveAsAction );
        mFileMenu->addSeparator();
        mExportMenu = mFileMenu->addMenu("Export");
        mExportMenu->addAction(mExportToPDFAction);
        mExportMenu->addAction(mExportToTabAction);
        mExportMenu->addAction(mExportToMusicXML);
        //mExportMenu->addAction(mExportToPNGAction);
        mFileMenu->addSeparator();
        mFileMenu->addAction ( mPrintAction );
        mFileMenu->addSeparator();
        mFileMenu->addAction ( mExitAction );

        menuBar()->addSeparator();
        mEditMenu = menuBar()->addMenu ( tr ( "&Edit" ) );
        QMenu *insertMenu = mEditMenu->addMenu("Insert");

        insertMenu->addAction(mInsertBarAction);
        insertMenu->addSeparator();
        insertMenu->addAction(mNote128Action);
        insertMenu->addAction(mNote64Action);
        insertMenu->addAction(mNote32Action);
        insertMenu->addAction(mNote16Action);
        insertMenu->addAction(mNote8Action);
        insertMenu->addAction(mNote4Action);
        insertMenu->addAction(mNote2Action);

        QMenu *zoomMenu = mEditMenu->addMenu("Zoom");
        zoomMenu->addAction( mZoomInAction);
        zoomMenu->addAction( mZoomOutAction);

        menuBar()->addSeparator();
        mHelpMenu = menuBar()->addMenu ( tr ( "&Help" ) );
        mHelpMenu->addAction ( mAboutAction );
    }

    void CEasyScoreMainWindow::createToolBars()
    {
        mFileToolBar = addToolBar ( tr ( "File" ) );
        mFileToolBar->addAction ( mNewAction );
        mFileToolBar->addAction ( mOpenAction );
        mFileToolBar->addAction ( mSaveAction );
        mFileToolBar->addAction ( mPrintAction );

        mEditToolbar = addToolBar ( tr ( "Edit" ) );
        mEditToolbar->addAction(mZoomInAction);
        mEditToolbar->addAction(mZoomOutAction);

        mNoteToolBar = addToolBar ( tr ( "Note" ) );
        //mNoteToolBar->addAction(mNote256Action);
        mNoteToolBar->addAction(mNote128Action);
        mNoteToolBar->addAction(mNote64Action);
        mNoteToolBar->addAction(mNote32Action);
        mNoteToolBar->addAction(mNote16Action);
        mNoteToolBar->addAction(mNote8Action);
        mNoteToolBar->addAction(mNote4Action);
        mNoteToolBar->addAction(mNote2Action);
        //mNoteToolBar->addAction(mNote1Action);


    }

    void CEasyScoreMainWindow::createStatusBar()
    {
        statusBar()->showMessage ( tr ( "Ready" ) );
    }

    bool CEasyScoreMainWindow::maybeSave()
    {
        if ( mApp->getScore() && mApp->getScore()->getModified() )
        {
            int ret = QMessageBox::warning ( this, CGlobals::getAppName() ,
                                             tr ( "The score has been modified.\n"
                                                  "Do you want to save your changes?" ),
                                             QMessageBox::Yes | QMessageBox::Default,
                                             QMessageBox::No,
                                             QMessageBox::Cancel | QMessageBox::Escape );
            if ( ret == QMessageBox::Yes )
                return save();
            else if ( ret == QMessageBox::Cancel )
                return false;
        }

        return true;
    }

    void CEasyScoreMainWindow::loadFile ( const QString &fileName )
    {
        QFile file ( fileName );

        if(mApp->load(file))
        {
            statusBar()->showMessage ( tr ( "File loaded" ), 2000 );
            setCurrentFile ( fileName );
        }
        else
        {
            QMessageBox::warning ( this, CGlobals::getAppName(),
                                   tr ( "Failed to load file %1" )
                                   .arg ( fileName ));
        }
    }

    bool CEasyScoreMainWindow::saveFile ( const QString &fileName )
    {
        QFile file ( fileName );
        if ( !mApp->save(file) )
        {
            QMessageBox::warning ( this, CGlobals::getAppName(),
                                   tr ( "Failed to save file %1" )
                                   .arg ( fileName ));
            return false;
        }

        setCurrentFile ( fileName );
        statusBar()->showMessage ( tr ( "File saved" ), 2000 );
        return true;
    }

    void CEasyScoreMainWindow::setCurrentFile ( const QString &fileName )
    {
        mApp->setCurrentFile(fileName);
        if(fileName.isEmpty())
            setWindowTitle ( tr ( "%1" ).arg (  CGlobals::getAppName()  ) );
        else
            setWindowTitle ( tr ( "%1[*] - %2" ).arg ( fileName ).arg ( CGlobals::getAppName() ) );
    }

    QString CEasyScoreMainWindow::strippedName ( const QString &fullFileName )
    {
        return QFileInfo ( fullFileName ).fileName();
    }

    void CEasyScoreMainWindow::keyReleaseEvent ( QKeyEvent * event )
    {
        //        QMainWindow::keyReleaseEvent ( event );

        //        switch ( event->key() )
        //        {
        //        case Qt::Key_0 : { mApp->setCurrentNoteValue ( NOTE_VALUE_DOUBLE_WHOLE ); break; }
        //        case Qt::Key_1 : { mApp->setCurrentNoteValue ( NOTE_VALUE_WHOLE ); break; }
        //        case Qt::Key_2 : { mApp->setCurrentNoteValue ( NOTE_VALUE_HALF ); break; }
        //        case Qt::Key_3 : { mApp->setCurrentNoteValue ( NOTE_VALUE_QUARTER ); break; }
        //        case Qt::Key_4 : { mApp->setCurrentNoteValue ( NOTE_VALUE_EIGHTH ); break; }
        //        case Qt::Key_5 : { mApp->setCurrentNoteValue ( NOTE_VALUE_SIXTEENTH ); break; }
        //        case Qt::Key_6 : { mApp->setCurrentNoteValue ( NOTE_VALUE_THIRTYSECOND ); break; }
        //        case Qt::Key_7 : { mApp->setCurrentNoteValue ( NOTE_VALUE_SIXTYFOURTH ); break; }
        //            //case Qt::Key_8 : { mApp->setCurrentNoteValue(NOTE_VALUE_HUNDREDTWENTYEIGTH); break; }
        //        }
    }

    void CEasyScoreMainWindow::addBar()
    {
        mApp->addBar();
    }

    void CEasyScoreMainWindow::setCurrentNote(QAction *action)
    {
        //if(action == mNote256Action)
        //    mApp->setCurrentNoteValue ( NOTE_VALUE_DOUBLE_WHOLE );
        if(action == mNote128Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_WHOLE );
        if(action == mNote64Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_HALF );
        if(action == mNote32Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_QUARTER );
        if(action == mNote16Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_EIGHTH );
        if(action == mNote8Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_SIXTEENTH );
        if(action == mNote4Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_THIRTYSECOND );
        if(action == mNote2Action)
            mApp->setCurrentNoteValue ( NOTE_VALUE_SIXTYFOURTH );
        //if(action == mNote1Action)
        //    mApp->setCurrentNoteValue ( NOTE_VALUE_HUNDREDTWENTYEIGTH );
    }

    void CEasyScoreMainWindow::exportToTab()
    {
        QString fileName =
                QFileDialog::getSaveFileName(this, tr("Export to TAB..."),
                                             QDir::home().path(),
                                             tr("Text files (*.txt)"));
        if (fileName.isEmpty())
            return;
        if(!fileName.endsWith(".txt"))
            fileName += ".txt";

        QFile file(fileName);

        if(file.exists())
            file.remove();

        if (mApp->exportTab(file))
        {
            statusBar()->showMessage(tr("File saved"), 2000);
            //setCurrentFile(fileName);
            return;
        }
        else
        {
            statusBar()->showMessage(tr("Saving failed"), 2000);
            return;
        }
    }

    void CEasyScoreMainWindow::exportToMusicXML()
    {
        QString fileName =
                QFileDialog::getSaveFileName(this, tr("Export to MusicXML..."),
                                             QDir::home().path(),
                                             tr("Text files (*.xml)"));
        if (fileName.isEmpty())
            return;
        if(!fileName.endsWith(".xml"))
            fileName += ".xml";

        QFile file(fileName);

        if(file.exists())
            file.remove();

        if (mApp->exportMusicXML(file))
        {
            statusBar()->showMessage(tr("File saved"), 2000);
            //setCurrentFile(fileName);
            return;
        }
        else
        {
            statusBar()->showMessage(tr("Saving failed"), 2000);
            return;
        }
    }

    void CEasyScoreMainWindow::exportToPDF()
    {
        QString fileName =
                QFileDialog::getSaveFileName(this, tr("Export to PDF..."),
                                             QDir::home().path(),
                                             tr("Text files (*.pdf)"));
        if (fileName.isEmpty())
            return;
        if(!fileName.endsWith(".pdf"))
            fileName += ".pdf";

        QFile file(fileName);

        if(file.exists())
            file.remove();

        if (mApp->exportToPDF(file))
        {
            statusBar()->showMessage(tr("File saved"), 2000);
            return;
        }
        else
        {
            statusBar()->showMessage(tr("Saving failed"), 2000);
            return;
        }
    }

    void CEasyScoreMainWindow::exportToPNG()
    {
       QString dir = QFileDialog::getExistingDirectory(this, tr("Choose a directory..."),
                                                                 "/home",
                                                                 QFileDialog::ShowDirsOnly
                                                                 | QFileDialog::DontResolveSymlinks);
        if (dir.isEmpty())
            return;

        if (mApp->exportImage(dir))
        {
            statusBar()->showMessage(tr("Files saved"), 2000);
            return;
        }
        else
        {
            statusBar()->showMessage(tr("Saving failed"), 2000);
            return;
        }
    }

    void CEasyScoreMainWindow::zoomIn()
    {
        mScoreSceneView->zoom(240);
    }

    void CEasyScoreMainWindow::zoomOut()
    {
        mScoreSceneView->zoom(-240);
    }
}

